<template>
	<view class="vi_formulaEditor" :id="id">
		<!-- 正文框 -->
		<view class="vi_formulaEditor_body" :class="bodyClass||''" :style="{'height':setting.bodyHight,'border-radius':setting.radius}">
			<scroll-view class="vi_full"
				scroll-x
				scroll-y
				scroll-with-animation
				:scroll-top="scrollTop"
				:scroll-left="scrollLeft"
				@touchmove.stop
				@click="tableClick">
				<view class="vi_formulaEditor_content">
					<view class="vi_formulaEditor_row" :class="{'vi_formulaEditor_pointStay':pointY==index}" v-for="(row, index) in dataList" :key="index" @click.stop="rowClick(index)">
						<view class="vi_formulaEditor_cell" v-for="(item, idx) in row" :key="idx" @click.stop="cellClick(index, idx, item)">
							<view class="vi_formulaEditor_point" v-if="pointY==index&&pointX==idx"></view>
							<view v-if="item.mode=='text'" :class="{'vi_bold':item.bold}"
								:style="{
									'color':item.color||'initial',
									'width':item.width||'auto',
								}">{{item.value}}
							</view>
							<view class="vi_formulaEditor_object" v-else-if="item.mode=='object'||item.icon">
								<vi-style-controller
									:type="item.type"
									:color="item.color||''"
									:plain="item.plain||false"
									:radius="item.radius||''"
									:borderWidth="item.borderWidth||''"
									active>
									<text class="iconfont" :class="item.icon" v-if="item.icon"></text>
									<text class="vi_formulaEditor_objectText" v-else>{{item.showValue}}</text>
								</vi-style-controller>
							</view>
						</view>
						<!-- 换行对象 -->
						<view class="vi_formulaEditor_cell">
							<view class="vi_formulaEditor_point" v-if="pointY==index&&pointX==row.length"></view>
							<view class="vi_formulaEditor_object vi_formulaEditor_return">↵</view>
						</view>
					</view>
				</view>
			</scroll-view>
		</view>
		<!-- 键盘 -->
		<view class="vi_formulaEditor_extraFrame" :class="{'vi_formulaEditor_extraFrame_hide':inputMode}">
			<view class="vi_formulaEditor_keyboard"
				:style="{
					'grid-template-rows': 'repeat(auto-fill, '+cellHeight+'em)',
					'grid-template-columns': 'repeat('+column+', 1fr)',
					'grid-auto-rows': cellHeight +'em',
					'grid-auto-columns': '1fr',
				}">
				<view class="vi_formulaEditor_keyboard_button" v-for="(item, index) in buttonList" :key="index"
					:style="{
						padding: space +'em',
						'grid-row-start': item.rowStart,
						'grid-row-end': item.rowEnd,
						'grid-column-start': item.colStart,
						'grid-column-end': item.colEnd,
					}">
					<vi-button @click="keyClick(item)"
						:type="item.active? item.activeType||item.type :item.type"
						:color="item.active? item.activeColor||item.color :item.color"
						borderBox
						width="100%"
						height="100%"
						:radius="keyRadius">
						<text class="vi_formulaEditor_keyboard_icon iconfont" :class="item.icon" v-if="item.icon"></text>
						<text :class="{'vi_bold':item.bold}" v-else>{{shiftAct&&item.shiftName?item.shiftName:item.name}}</text>
					</vi-button>
				</view>
			</view>
			
			<!-- 自定义附加组件，键盘框内 -->
			<fieldsMenu ref="fieldsMenu"
				:type="setting.type"
				:color="color"
				:dataSet="extraData"
				:text="textSetting"
				@event="extraEvent"></fieldsMenu>
			<functionMenu ref="functionMenu"
				:type="setting.type"
				:color="color"
				:dataSet="extraData"
				:text="textSetting"
				@event="extraEvent"></functionMenu>
			<specialMenu ref="specialMenu"
				:type="setting.type"
				:color="color"
				:dataSet="extraData"
				:text="textSetting"
				@event="extraEvent"></specialMenu>
		</view>
		<!-- 输入框 -->
		<view class="vi_formulaEditor_inputFrame" :class="{'vi_formulaEditor_inputFrame_act':inputMode}">
			<view class="vi_formulaEditor_inputBox" :style="{'border-radius':setting.radius}">
				<input class="input" v-model="inputValue" :focus="inputFocus" />
			</view>
			<view class="vi_formulaEditor_inputTools">
				<view class="vi_formulaEditor_inputButton">
					<vi-button
						width="100%"
						height="100%"
						:borderWidth="0"
						:type="setting.type"
						:color="color"
						:radius="setting.radius"
						@click="freeInput">{{textSetting.insert}}</vi-button>
				</view>
				<view class="vi_formulaEditor_inputButton">
					<vi-button
						width="100%"
						height="100%"
						:borderWidth="0"
						type="default"
						:radius="setting.radius"
						@click="closeInput">{{textSetting.returnKeyboard}}</vi-button>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	// 本组件不支持自动换行，不支持文字选中
	import keyboardData from "./keyboard.js"
	import keyFunction from "./keyFunction.js"
	//自定义附加组件
	import fieldsMenu from "./components/fieldsMenu.vue"
	import functionMenu from "./components/functionMenu.vue"
	import specialMenu from "./components/specialMenu.vue"
	
	export default {
		name:"viFormulaEditor",
		components:{
			//自定义附加组件
			fieldsMenu,
			functionMenu,
			specialMenu,
		},
		props: {
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:null
			},
			radius:{
				type:[String,Number,null],
				default:null
			},
			keyboard:{
				type:[String,null],
				default:"",
			},
			value:{
				type:[String,null],
				default:""
			},
			//内容区域高度
			bodyHight:{
				type:[String,null],
				default:""
			},
			bodyClass:{
				type:[String,null],
				default:""
			},
			//附加数据集，用于自定义组件
			dataSet:{
				type:[Object,null],
				default:()=>({})
			},
			//文字自定义
			text:{
				type:[Object,null],
				default:()=>({})
			}
		},
		data() {
			return {
				spaceWidth:"0.5em",	//空格显示宽度，固定
				id:"",				//组件id
				inValue:"",			//公式字符串暂存
				buttonList:[],		//键盘按钮数据
				dataList:[],		//公式数据
				currKeyboard:"",	//当前键盘名
				column:0,			//网格列数
				cellWidth:0,		//网格单元格宽，百分比值
				cellHeight:0,		//网格单元格高，单位em
				space:0,			//间距，单位em
				keyRadius:"",		//圆角
				useShift:false,		//使用shift键
				shiftAct:false,		//shift激活
				pointX:0,			//光标位置，X轴元素
				pointY:0,			//光标位置，Y轴行
				scrollTop:0,		//滚动条位置
				scrollLeft:0,		//滚动条位置
				boxPoint:null,		//滚动框坐标
				inputMode:false,	//自由输入模式
				inputValue:"",		//输入框值
				inputFocus:false,	//输入框获得焦点
				dicText:{
					insert:"插入",
					returnKeyboard:"键盘",
					tipCopySuccess:"公式已复制到缓存",
					tipPasteSuccess:"已粘贴公式",
					tipResetSuccess:"公式已重置",
					tipNoClipboard:"未复制公式",
				}
			}
		},
		computed: {
			setting(){
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					radius: this.$api.isDefined(this.radius)? this.radius :"0.5em",
					bodyHight: this.bodyHight ||"7.5em",
					keyboard: this.keyboard ||"decimal",
				}
			},
			extraData(){
				let dataSet = this.dataSet;
				if(!dataSet || !this.$api.isObject(dataSet)){
					return {}
				}
				return dataSet
			},
			textSetting(){
				if(this.$api.isObject(this.text)){
					return Object.assign({},this.dicText,this.text)
				}
				return this.dicText
			}
		},
		methods: {
			//初始化键盘
			initKeyboard(){
				let keyboard = keyboardData[this.currKeyboard];
				this.column = keyboard.column ||5;
				this.cellWidth = 100/keyboard.column;
				this.cellHeight = keyboard.cellHeight ||2.5;
				this.space = keyboard.space/2 ||0;
				this.keyRadius = keyboard.radius ||"";
				this.useShift = keyboard.useShift ||false;
				this.buttonList = keyboard.keys;
				if(!this.useShift){
					this.shiftAct =false
				}
				//校验参数值
				for(let item of this.buttonList){
					if(!item.rowStart){
						item["rowStart"] =""
					}
					if(!item.rowEnd){
						item["rowEnd"] =""
					}
					if(!item.colStart){
						item["colStart"] =""
					}
					if(!item.colEnd){
						item["colEnd"] =""
					}
					if(!item.type){
						item["type"] ="default"
					}
					if(!item.color){
						item["color"] =""
					}
					if(!item.activeType){
						item["activeType"] =item.type
					}
					if(!item.activeColor){
						item["activeColor"] =item.color
					}
				}
			},
			//按键点击
			keyClick(item){
				if(item.func){//使用功能
					let func = keyFunction[item.func];
					if(func){
						func(this, this.dataList, item)
					}
				}else{//一般输入
					keyFunction["sysInput"](this, this.dataList, item)
				}
			},
			//内容点击，变更坐标点
			cellClick(index, idx, item){
				this.pointY = index;
				this.pointX = idx +(item.mode!="text"?1:0);
				this.scrollToPoint();
			},
			//行点击，坐标置尾
			rowClick(index){
				this.pointY = index;
				this.pointX = this.dataList[index].length;
				this.scrollToPoint();
			},
			//行外点击，坐标置于尾行行尾
			tableClick(){
				this.pointY = (this.dataList.length ||1) -1;
				this.pointX = this.dataList[this.pointY].length;
			},
			//滚动条移动到光标点
			scrollToPoint(){
				this.$nextTick(()=>{
					const views = uni.createSelectorQuery().in(this);
					views.selectAll(`#${this.id} .vi_formulaEditor_pointStay .vi_formulaEditor_cell`)
						.fields({
							size: true
						}, (data) => {
							// console.log("查询",data);
							let w = 0;
							for(let i=0; i<this.pointX -8; i++){//前面预留8个字符
								w += data[i].width
							}
							this.scrollLeft = w;
							this.scrollTop = data[0].height *this.pointY -20;
						})
						.exec()
				})
			},
			//附加组件调用功能
			extraEvent(key, ...data){
				let func = keyFunction[key];
				if(func){
					func(this, this.dataList, ...data)
				}else{
					console.error("公式编辑器自定义功能调用错误：",key)
				}
			},
			//自由输入内容，的插入
			freeInput(){
				let x = this.pointX,
					y = this.pointY,
					str = this.inputValue,
					len = str.length,
					strArr =[];
				//无字符则退出
				if(!str&&str!==0){
					return
				}
				//把内容拆分成字符对象
				for(let i=0; i<len; i++){
					let value = str.charAt(i);
					let res = {
						mode:"text",
						value
					}
					//如果是空白符则增加宽度
					if(value.trim()==""){
						res["value"] = " ";
						res["width"] = this.spaceWidth;
					}
					strArr.push(res)
				}
				this.dataList[y].splice(x, 0, ...strArr);
				this.pointX += len;
				this.scrollToPoint();//滚动条移动到光标位置
				this.inputValue ="";
			},
			//关闭自由输入框
			closeInput(){
				this.inputValue ="";
				this.extraEvent('sysSwitchInput');
			},
			//刷新渲染
			update(){
				this.$forceUpdate()
			},
			//初始化数据
			initData(){
				keyFunction["parseData"](this, this.dataList, this.inValue);
			},
			//获取格式化结果
			getData(){
				return keyFunction["formatData"](this, this.dataList)
			}
		},
		watch:{
			"value":{
				immediate:true,
				handler(newVal){
					this.inValue = newVal ||"";
					if(newVal){
						this.initData()
					}else{
						this.dataList =[[]]
					}
					//光标重置
					this.pointY =0;
					this.pointX =0;
				}
			},
		},
		created() {
			this.id = `el${Math.ceil(Math.random() * 10e10).toString(36)}`;
			this.currKeyboard = this.setting.keyboard || keyboardData[Object.keys(keyboardData)[0]];
			this.initKeyboard();
		},
	}
</script>

<style lang="scss">
.vi_formulaEditor{
	overflow: hidden;
	.vi_formulaEditor_body{
		margin-bottom: 0.5em;
		padding: 0.5em;
		border: 1px solid #ddd;
		min-height: 6em;
		line-height: 1.5;
		box-sizing: border-box;
	}
	.vi_formulaEditor_content{
		display: table;
		min-width: 100%;
	}
	.vi_formulaEditor_row{
		white-space: nowrap;
		padding-bottom: 0.5em;
	}
	.vi_formulaEditor_cell{
		display: table-cell;
		margin-right: 0;
		position: relative;
	}
	.vi_formulaEditor_point{
		position: absolute;
		left: 0;
		top: 0;
		height: 100%;
		border: 1px solid #c00;
		animation: point 1s linear infinite;
	}
	.vi_formulaEditor_object{
		padding: 0 0.1em;
		margin: 0 0.25em;
	}
	.vi_formulaEditor_return{
		color: #ccc;
	}
	.vi_formulaEditor_objectText{
		padding: 0 0.25em;
		white-space: nowrap;
	}
	.vi_formulaEditor_extraFrame{
		position: relative;
		&.vi_formulaEditor_extraFrame_hide{
			height: 0;
			padding-bottom: 0;
			overflow: hidden;
		}
	}
	.vi_formulaEditor_keyboard{
		width: 100%;
		display: grid;
	}
	.vi_formulaEditor_keyboard_button{
		box-sizing: border-box;
	}
	.vi_formulaEditor_keyboard_icon{
		font-size: 120%;
	}
	.vi_formulaEditor_inputFrame{
		background-color: white;
		display: flex;
		align-items: center;
		margin-bottom: -2em;
		&.vi_formulaEditor_inputFrame_act{
			margin-bottom: 0
		}
		.vi_formulaEditor_inputBox{
			flex-grow: 1;
			display: flex;
			align-items: center;
			height: 2em;
			padding: 0 0.5em;
			border: 1px solid #ddd;
			box-sizing: border-box;
			.input{
				width: 100%;
			}
		}
		.vi_formulaEditor_inputTools{
			flex-shrink: 0;
			display: flex;
		}
		.vi_formulaEditor_inputButton{
			width: 5em;
			height: 2em;
			margin-left: 0.5em;
		}
	}
	@keyframes point{
		0%,29%{opacity: 0}
		30%,100%{opacity: 1}
	}
}
.vi_bold{
	font-weight: bold;
}
.vi_full{
	width: 100%;
	height: 100%;
}
</style>